﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace BingVis.WPFClient
{
    /// <summary>
    /// The concept for this class comes from PRISM (Composite Application Guidance)
    /// </summary>
    /// <typeparam name="ParmType">The type of the Parameter to use for the command</typeparam>
    public class DelegateCommand<ParmType> : ICommand
    {

        private Action<ParmType> _command;
        private Predicate<ParmType> _canExecute;
        private bool _tracksExecuted;

        // for testing that a command ran.
        public bool CommandExecuted { get; set; }

        public DelegateCommand(Action<ParmType> command, bool tracksExecuted)
            : this(command)
        {
            _tracksExecuted = tracksExecuted;
        }

        public DelegateCommand(Action<ParmType> command, Predicate<ParmType> canExecute)
            : this(command, canExecute, false)
        {

        }

        public DelegateCommand(Action<ParmType> command)
            : this(command, (x) => true, false)
        {

        }

        /// <summary>
        /// Creates a new DelegateCommand with the specified values.
        /// </summary>
        /// <param name="command">The logic to execute.</param>
        /// <param name="canExecute">The logic to determine if a command can execute.</param>
        /// <param name="tracksExecuted">A flag that tells the command not to automatically set CommandExecuted to true.</param>
        public DelegateCommand(Action<ParmType> command, Predicate<ParmType> canExecute, bool tracksExecuted)
        {
            _command = command;
            _canExecute = canExecute;
            _tracksExecuted = tracksExecuted;
        }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            return _canExecute.Invoke((ParmType)parameter);
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {   
            this.CommandExecuted = false;

            if (CanExecute(parameter))
            {
                _command.Invoke((ParmType)parameter);

                if (!_tracksExecuted) 
                    this.CommandExecuted = true;
            }
        }

        #endregion
    }
}
